package com.me.singleton;

/**
 * @author inttom
 * @date 2022/2/13
 *
 * volatile:保证一致性,不保证原子性,防止指令重拍
 * 共享变量,防止指令重排
 * 这里必须加 volalite 的原因: new 对象的过程分为三步: 1. 分配空间 2. 初始化对象 3. 指向对象内存地址
 * 第二步和第三步可能被编译器自动重排(执行顺序可能会变),导致判断非空但是实际拿到的对象还未完成初始化
 * 举例:如果先指向内存空间执行,这是对象为空,另一个线程有可能进入并返回未初始化的对象
 *
 * 结论:强烈推荐使用!
 */
public class SingletonTest06 {
    public static void main(String[] args) {
        new Thread(new MyThread4()).start();
        new Thread(new MyThread4()).start();
    }
}

class MyThread4 implements Runnable {

    @Override
    public void run() {
        Singleton6 instance = Singleton6.getInstance();
        System.out.println(Thread.currentThread().getName() + ": " + instance.hashCode());
    }
}

/**
 * 懒汉式,双重检查,效率+多线程安全
 */
class Singleton6 {
    private static volatile Singleton6 instance;
    private Singleton6() {
    }

    /**
     * 提供一个静态的公有方法,当使用到该方法的时候,才会去创建 instance
     * 懒汉式
     */
    public static Singleton6 getInstance() {
        if (instance == null) {
            synchronized (Singleton6.class) {
                if (instance == null) {
                    instance = new Singleton6();
                }
            }
        }
        return instance;
    }
}


